package edu.hawaii.duedates.tests;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import org.apache.commons.cli.ParseException;
import org.junit.Ignore;
import org.junit.Test;

import edu.hawaii.duedates.CommandLineArgs;

/**
 * Unit tests for class CommandLineArgs.
 * 
 * @author John Ancheta, Daniel Arakaki, Mari-Lee Flestado
 * 
 */
public class TestCommandLineArgs {
  /** Static variable.*/
  public static final String verbose = "-verbose";
  /** Static variable. */
  public static final String sort = "-sort";
  /** Static variable.*/
  public static final String uhm = "-uhm";
  /** Static variable.*/
  public static final String hsl = "-hsl";
  /** Static variable.*/
  public static final String option1 = "option1";
  /** Static variable.*/
  public static final String option2 = "option2";
  /** Static variable.*/
  public static final String option3 = "option3";
  /** Static variable.*/
  public static final String option4 = "option4";
  /** Static variable.*/
  public static final String SORT_LIBRARY = "library";
  /** Static variable.*/
  public static final String WITHIN_OPTION = "-within";
  /** Static variable.*/
  public static final String WAKEUP_OPTION = "-wakeup";
  /** Static variable.*/
  public static final String EMAIL_OPTION = "-email";
  /** Static variable.*/
  public static final String CONSOLE_OPTION = "-console";
  /** Static variable.*/
  public static final String SORT_OPTION = "-sort";

  /** Static variable.*/
  public static final String MY_SMTP_SERVER = "mysmtpserver";
  
  /**
   * Test CommandLineArgs.parse with null args.
   * 
   * @throws ParseException for incorrect command line argument.
   */
  @Test (expected = ParseException.class)
  public void testParseWithNull() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(null);
  }

  /**
   * Test CommandLineArgs.parse with -verbose option in args.
   * 
   * @throws ParseException for incorrect command line argument.
   */
  @Test
  public void testParseWithOptionVerbose() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {verbose, CONSOLE_OPTION,
                                        uhm, option1, option2,
                                        hsl,option3,option4});
    assertTrue("Should be true testParseWithOptionVerbose.", commandLineArgs.hasVerboseOption());
  }
 
  /**
   * Test CommandLineArgs.parse with -verbose option in args.
   * 
   * @throws ParseException for incorrect command line argument.
   */
  @Test
  public void testParseWithOptionNoVerbose() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, uhm, option1,option2});
    assertFalse("Should be false b.", commandLineArgs.hasVerboseOption());
  }
  
  /**
   * Test CommandLineArgs.parse with -uhm option in args.
   * 
   * @throws ParseException for incorrect command line argument.
   */
  @Test
  public void testParseWithValidUhmOptions() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, uhm, option1,option2});
    assertTrue("Should be true -uhm.", commandLineArgs.hasUhmOption());
    assertEquals("Should be the same -uhm option1", option1, commandLineArgs.getUhmId());
    assertEquals("Should be the same -uhm option2", option2, commandLineArgs.getUhmLastName());
  }
  
  /**
   * Test CommandLineArgs.parse with -hsl in args.
   * 
   * @throws ParseException for incorrect command line argument.
   */
  @Test
  public void testParseWithValidHslOptions() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, hsl,option1,option2});
    assertTrue("Should be true -hsl.", commandLineArgs.hasHslOption());
    assertEquals("Should be the same -hsl option1", option1, 
                 commandLineArgs.getHslId());
    assertEquals("Should be the same -hsl option2", option2, 
                 commandLineArgs.getHslLastFourDigitsForPhoneNumber());
  }
  
  /**
   * Test CommandLineArgs.parse with -uhm and -hsl in args.
   * 
   * @throws ParseException for incorrect command line argument.
   */
  @Test
  public void testParseWithValidUhmAndHslOptions() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, uhm, option1, option2,
                                        hsl,option3,option4});
    assertTrue("Should be true a.", commandLineArgs.hasUhmOption());
    assertEquals("Should be the same a", option1, commandLineArgs.getUhmId());
    assertEquals("Should be the same b", option2, commandLineArgs.getUhmLastName());
    assertTrue("Should be true b.", commandLineArgs.hasHslOption());
    assertEquals("Should be the same c", option3, 
                 commandLineArgs.getHslId());
    assertEquals("Should be the same d", option4, 
                 commandLineArgs.getHslLastFourDigitsForPhoneNumber());
  }
  
  /**
   * Test CommandLineArgs.parse with no required -uhm and/or -hsl in args.
   * 
   * @throws ParseException for incorrect command line argument.
   */
  @Test (expected = ParseException.class)
  public void testParseWithNoUhmAndHslOptions() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {verbose});
    
  }
  
  /**
   * Test CommandLineArgs.parse with -sort library in args.
   * 
   * @throws ParseException for incorrect command line argument.
   */
  @Test
  public void testParseWithSortLibrary() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {verbose, CONSOLE_OPTION,
                                        sort, SORT_LIBRARY,
                                        uhm, option1, option2,
                                        hsl,option3,option4});
    assertTrue("Should be true c.", commandLineArgs.hasSortOption());
    assertEquals("Should be the same e", SORT_LIBRARY, commandLineArgs.getSortValue());
  }
  
  /**
   * Test CommandLineArgs.parse with -sort due date in args.
   * 
   * @throws ParseException for incorrect command line argument.
   */
  @Test
  public void testParseWithSortDueDate() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {verbose,CONSOLE_OPTION,
                                        sort, "duedate",
                                        uhm, option1, option2,
                                        hsl,option3,option4});
    assertTrue("Should be true c.", commandLineArgs.hasSortOption());
    assertEquals("Should be the same e", "duedate", commandLineArgs.getSortValue());
  }
  
  /**
   * Test CommandLineArgs.parse with -sort due date|library in args.
   * 
   * @throws ParseException for incorrect command line argument.
   */
  @Test
  public void testParseWithDefaultSort() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {verbose,CONSOLE_OPTION,
                                        uhm, option1, option2,
                                        hsl,option3,option4});
    assertFalse("Should be false c.", commandLineArgs.hasSortOption());
    assertEquals("Should be the same f", SORT_LIBRARY, commandLineArgs.getSortValue());
  }
  
  /**
   * Test CommandLineArgs.parse with -within integer in args.
   * 
   * @throws ParseException for incorrect command line argument.
   */
  @Test
  public void testParseWithWithin() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {verbose,CONSOLE_OPTION,
                                        "-within", "2",
                                        uhm, option1, option2,
                                        hsl,option3,option4});
    assertTrue("Should be true d.", commandLineArgs.hasWithinOption());
    assertEquals("Should be the same g", 2, commandLineArgs.getWithinValue());
  }
  
  /**
   * Test CommandLineArgs.parse default value for -within.
   * 
   * @throws ParseException for incorrect command line argument.
   */
  @Test
  public void testParseWithWithinDefaultValue() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {verbose,CONSOLE_OPTION,
                                        uhm, option1, option2,
                                        hsl,option3,option4});
    assertFalse("Should be false d.", commandLineArgs.hasWithinOption());
    assertEquals("Should be the same h", 0, commandLineArgs.getWithinValue());
  }
  
  /**
   * Test CommandLineArgs -sort option with string other than library or due date.
   * 
   * @throws ParseException for incorrect argument for -sort.
   */
  @Test (expected = ParseException.class)
  public void testOptionSortWithInvalidArgument() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {sort, "libraryduedate",
                                        uhm, option1, option2});
  }
  /**
   * Test CommandLineArgs -sort option with more than one required option.
   * 
   * @throws ParseException for too many arguments.
   */
  @Test (expected = ParseException.class)
  public void testOptionSortWithExtraArguments() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {sort, SORT_LIBRARY, "extra", "anthorextra",
                                        uhm, option1, option2});
  }
  /**
   * Test -within with no argument.
   * 
   * @throws ParseException for invalid argument.
   */
  @Test (expected = ParseException.class)
  public void testWithinWithNoArgument() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {WITHIN_OPTION,
                                        uhm, option1, option2});
  }
  /**
   * Test -within with non integer argument.
   * 
   * @throws ParseException for invalid argument.
   */
  @Test (expected = ParseException.class)
  public void testWithinWithNonIntegerArgument() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {WITHIN_OPTION, "one",
                                        uhm, option1, option2});
  }
  
  /**
   * Test -within with negative argument.
   * 
   * @throws ParseException for invalid argument.
   */
  @Test (expected = ParseException.class)
  public void testWithinWithNegativeArgument() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {WITHIN_OPTION, "-1",
                                        uhm, option1, option2});
  }
  
  /**
   * Test has valid -wakeup option. 
   *
   * @throws ParseException For invalid args.
   */
  @Test (expected = ParseException.class)
  public void testWakeupOptionWithNoArgs() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {WAKEUP_OPTION,
                                        uhm, option1, option2});
    fail("Should not reach here.");
  }
  
  /**
   * Test has valid -wakeup option. 
   *
   * @throws ParseException For invalid args.
   */
  @Test (expected = ParseException.class)
  public void testWakeupOptionWithExtraArgs() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {WAKEUP_OPTION, "0", "44", 
                                        uhm, option1, option2});
    fail("Should not reach here.");
  }
  
  /**
   * Test has valid -wakeup option. 
   *
   * @throws ParseException For invalid args.
   */
  @Test
  public void testHasWakeupOption() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {WAKEUP_OPTION, "0",CONSOLE_OPTION,
                                        uhm, option1, option2});
    assertTrue("Should be true.", commandLineArgs.hasWakeupOption());
  }
  
  /**
   * Test has no -wakeup option.
   *
   * @throws ParseException For invalid args.
   */
  @Test
  public void testHasNoWakeupOption() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, uhm, option1, option2});
    assertFalse("Should be false a.", commandLineArgs.hasWakeupOption());
  }
  
  /**
   * Test has valid -wakeup option. 
   *
   * @throws ParseException For invalid args.
   */
  @Test (expected = ParseException.class)
  public void testHasWakeupOptionWithNonDoubleArg() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {WAKEUP_OPTION, "AAA",
                                        uhm, option1, option2});
    fail("Should not reach here.");
  }
  
  /**
   * Test has valid -wakeup option. 
   *
   * @throws ParseException For invalid args.
   */
  @Test
  public void testGetWakeupOptionArgValue() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {WAKEUP_OPTION, "2.5",CONSOLE_OPTION,
                                        uhm, option1, option2});
    assertEquals("Should be equal 4.", 2.5, commandLineArgs.getWakeupValue(), 0.00001);
  }
  
  /**
   * Test has -email option.
   *
   * @throws ParseException For invalid args.
   */
  @Test
  public void testHasEmailOption() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {EMAIL_OPTION, "myemail", MY_SMTP_SERVER,
                                        uhm, option1, option2});
    assertTrue("Should be true.", commandLineArgs.hasEmailOption());
  }
  
  /**
   * Test has no -email option.
   *
   * @throws ParseException For invalid args.
   */
  @Test
  public void testHasNoEmailOption() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, uhm, option1, option2});
    assertFalse("Should be false.", commandLineArgs.hasEmailOption());
  }
  
  /**
   * Test has -email option with no arguments.
   *
   * @throws ParseException For invalid args.
   */
  @Test (expected = ParseException.class)
  public void testHasEmailOptionWithNoArguments() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {EMAIL_OPTION,
                                        uhm, option1, option2});
  }
  /**
   * Test has -email option with just one argument.
   *
   * @throws ParseException For invalid args.
   */
  @Ignore
  @Test (expected = ParseException.class)
  public void testHasEmailOptionWithOneArgument() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {EMAIL_OPTION, "one",
                                        uhm, option1, option2});
  }
  /**
   * Test has -email option with too many arguments.
   *
   * @throws ParseException For invalid args.
   */
  @Test (expected = ParseException.class)
  public void testHasEmailOptionWithTooManyArguments() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {EMAIL_OPTION, "one", "two", "three",
                                        uhm, option1, option2});
  }
  
  /**
   * Test has -email option for getEmailAccountValue.
   *
   * @throws ParseException for invalid args.
   */
  @Test
  public void testGetEmailAccountValue() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {EMAIL_OPTION, "myemailaccount", MY_SMTP_SERVER,
                                        uhm, option1, option2});
    assertEquals("Should be equal 5.", "myemailaccount", commandLineArgs.getEmailAddressValue());
  }
  
  /**
   * Test has -email option for getEmailAccountValue.
   *
   * @throws ParseException for invalid args.
   */
  @Test
  public void testGetEmailSmtpServerValue() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {EMAIL_OPTION, "myemailaccount", MY_SMTP_SERVER,
                                        uhm, option1, option2});
    assertEquals("Should be equal 1.", MY_SMTP_SERVER, commandLineArgs.getEmailSmtpServerValue());
  }
  
  /**
   * Test has no -email option for getEmailAccountValue .
   *
   * @throws ParseException for invalid args.
   */
  @Test
  public void testGetEmailAccountValueWithNoEmailOption() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, uhm, option1, option2});
    assertEquals("Should be equal 2.", null, commandLineArgs.getEmailAddressValue());
  }
  
  /**
   * Test has no -email option for getEmailAccountValue.
   *
   * @throws ParseException for invalid args.
   */
  @Test
  public void testGetEmailSmtpServerValueWithNoEmailOption() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, uhm, option1, option2});
    assertEquals("Should be equal 3.", null, commandLineArgs.getEmailSmtpServerValue());
  }
  
  /**
   * Test has -console option.
   *
   * @throws ParseException for invalid args.
   */
  @Test
  public void testHasConsole() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION,
                                        uhm, option1, option2});
    assertTrue("Should be true.", commandLineArgs.hasConsoleOption());
  }
  
  /**
   * Test has no -console option.
   *
   * @throws ParseException for invalid args.
   */
  @Test (expected = ParseException.class)
  public void testHasNoConsole() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {uhm, option1, option2});
  }
  
  /**
   * Test has no -console option.
   *
   * @throws ParseException for missing -uhm and -hsl.
   */
  @Test (expected = ParseException.class)
  public void testHasNoUhmOrHsl() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION});
  }
  /**
   * Test has no -console option.
   *
   * @throws ParseException for missing -uhm and -hsl.
   */
  @Test (expected = ParseException.class)
  public void testSortOptionIsNotDueDatesOrLibrary() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, SORT_OPTION, "duedateslibrary"});
  }
  /**
   * Test has no -console option.
   *
   * @throws ParseException for missing -uhm and -hsl.
   */
  @Test (expected = ParseException.class)
  public void testInvalidWithinOption() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, WITHIN_OPTION, "duedateslibrary"});
  }
  /**
   * Test has no -console option.
   *
   * @throws ParseException for missing -uhm and -hsl.
   */
  @Test (expected = ParseException.class)
  public void testInvalidWakeupOption() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, WAKEUP_OPTION, "duedateslibrary"});
  }
  /**
   * Test has no -console option.
   *
   * @throws ParseException for missing -uhm and -hsl.
   */
  @Test (expected = ParseException.class)
  public void testInvalidWakeupNoOption() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, WAKEUP_OPTION,
                                        uhm, "id", "6pin"});
  }
  /**
   * Test has no -console option.
   *
   * @throws ParseException for missing -uhm and -hsl.
   */
  @Test (expected = ParseException.class)
  public void testInvalidWakeupOptionWithNegative() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, WAKEUP_OPTION, "-5"});
  }
  /**
   * Test has no -console option.
   *
   * @throws ParseException for missing -uhm and -hsl.
   */
  @Test
  public void testInvalidWakeupOptionWithPositive() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
 
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, WAKEUP_OPTION, "5",
                                uhm, "id", "pin1"});
    double value = commandLineArgs.getWakeupValue();
    assertEquals("should be equal.", 5, value, 0.0001);
  }
  /**
   * Test has no -console option.
   *
   * @throws ParseException for missing -uhm and -hsl.
   */
  @Test (expected = ParseException.class)
  public void testWithinNoOption() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, WITHIN_OPTION,
                                        uhm, "id", "2pin"});
  }
  /**
   * Test has no -console option.
   *
   * @throws ParseException for missing -uhm and -hsl.
   */
  @Test
  public void testWithinWithPositiveNumber() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, WITHIN_OPTION, "3",
                                        uhm, "id", "3pin"});
    int value = commandLineArgs.getWithinValue();
    assertEquals("should be equal.", 3, value);
  }
  /**
   * Test has no -console option.
   *
   * @throws ParseException for missing -uhm and -hsl.
   */
  @Test (expected = ParseException.class)
  public void testWithinWithNonNumber() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, WITHIN_OPTION, "three",
                                        uhm, "id", "4pin"});
  }
  /**
   * Test has no -console option.
   *
   * @throws ParseException for missing -uhm and -hsl.
   */
  @Test (expected = ParseException.class)
  public void testWithinWithNegativeNumber() throws ParseException {
    CommandLineArgs commandLineArgs = new CommandLineArgs();
    commandLineArgs.parse(new String[] {CONSOLE_OPTION, WITHIN_OPTION, "-3",
                                        uhm, "id", "5pin"});
  }
}
